#ifndef MUTEXMAP_H
#define MUTEXMAP_H

#include <QtCore/QMap>
#include <QtCore/QMutexLocker>

template<typename tKey, typename tValue>
class MutexMap : public QMap<tKey, tValue>
{
public:
    typedef void(*func_void_callback)(const tKey& k, tValue& v, void* pData);
    typedef bool(*func_bool_callback)(const tKey& k, tValue& v, void* pData);
    typedef void(*func_void_valuecall)(tValue& v, void* pData);
    typedef tValue(*func_value_voidcall)(const tKey& k, void* pData);
    MutexMap()
    : m_mutex(QMutex::Recursive) {
    }
    ~MutexMap() {}

    void insert(const tKey & k, const tValue & v) {
        QMutexLocker locker(&m_mutex);
        QMap::insert(k, v);
    }

    QList<tKey> keys() {
        QMutexLocker locker(&m_mutex);
        return QMap::keys();
    }

    bool contains(const tKey& k) {
        QMutexLocker locker(&m_mutex);
        return QMap::contains(k);
    }

    tValue value(const tKey& k, const tValue& defV) {
        QMutexLocker locker(&m_mutex); 
        return QMap::value(k, defV);
    }

    tValue value(const tKey& k) {
        QMutexLocker locker(&m_mutex);
        return this->QMap::operator[](k);
    }

    tValue& operator[](const tKey & k) {
        QMutexLocker locker(&m_mutex);
        return this->QMap::operator[](k);
    }

    tValue value2(const tKey& k, func_value_voidcall cbFunc, void* pData) {
        QMutexLocker locker(&m_mutex);
        if (QMap::contains(k)) {
            return this->QMap::operator[](k);
        }
        else {
            tValue v = cbFunc(k, pData);
            QMap::insert(k, v);
            return v;
        }
    }

    void clear(func_void_callback cbFunc, void* pData = NULL) {
        QMutexLocker locker(&m_mutex); 
        for(Iterator it = begin(); it != end(); ++it) {
            if(NULL != cbFunc) cbFunc(it.key(), it.value(), pData);
        }
        QMap::clear();
    }

    void clear(func_void_valuecall cbCall, void* pData = NULL) {
        QMutexLocker locker(&m_mutex); 
        for(Iterator it = begin(); it != end(); ++it) {
            if(NULL != cbCall) cbCall(it.value(), pData);
        }
        QMap::clear();
    }
 
    void clear() {
        QMap::clear();
    }

    bool valueCall(const tKey& k, func_void_callback cbFunc, void* pData ) {
        QMutexLocker locker(&m_mutex);
        if( QMap::contains(k) ) {
            cbFunc(k, this->QMap::operator[](k), pData);
            return true;
        } else {
            return false;
        }
    }

    bool valueCall(const tKey& k, func_void_valuecall cbFunc, void* pData) {
        QMutexLocker locker(&m_mutex);
        if( QMap::contains(k) ) {
            cbFunc(this->QMap::operator[](k), pData);
            return true;
        } else {
            return false;
        }
    }

    bool iterateCall(func_bool_callback cbFunc, void* pData) {
        if( NULL == cbFunc ) {
            return false;
        }
        QMutexLocker locker(&m_mutex);
        for(Iterator it = begin(); it != end(); ++it) {
            if( cbFunc(it.key(), it.value(), pData) ) {
                return true;
            }
        }
        return false;
    }

    void iterateCall2(func_void_callback cbFunc, void* pData) {
        if (NULL == cbFunc) {
            return ;
        }
        QMutexLocker locker(&m_mutex);
        for (Iterator it = begin(); it != end(); ++it) {
            cbFunc(it.key(), it.value(), pData);
        }
    }

    void iterateCall(func_void_valuecall cbFunc, void* pData) {
        if( NULL == cbFunc ) {
            return;
        }
        QMutexLocker locker(&m_mutex);
        for(Iterator it = begin(); it != end(); ++it) {
            cbFunc(it.value(), pData);
        }
    }

    tValue take(const tKey &key) {
        QMutexLocker locker(&m_mutex);
        return QMap::take(key);
    }

    tValue takeFirst(const tValue& defV) {
        QMutexLocker locker(&m_mutex);
        if (QMap::size() == 0){
            return defV;
        }
        return QMap::take(QMap::firstKey());
    }

    int remove(const tKey& key) {
        QMutexLocker locker(&m_mutex);
        return QMap::remove(key);
    }

private:
    QMutex  m_mutex;
};

#endif // MUTEXMAP_H
